package cn.edu.bit.dm;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;


import cn.edu.bit.dm.dao.BaseDao;
import cn.edu.bit.req.Request;
import cn.edu.bit.dto.WebPage;

@Component
@Scope("prototype")
public class Handler implements Runnable {
	
	private Socket socket;
	@Autowired
	@Qualifier("defaultDao")
	private BaseDao dao;
	@Autowired
	private Integer recordsPerPage;
	private static final Log logger = LogFactory.getLog(Handler.class);

	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	
	public Handler(){}
	
	public Handler(Socket socket){
		this.socket=socket;
	}

	public String getPreview(String content, String[] keywords){
		StringBuffer sb = new StringBuffer();
		for(String keyword : keywords){
			int index = content.indexOf(keyword);
			if(index==-1){
				continue;
			}
			int charsBeforeKeyword = getCharsBeforeKeyword(index);
			int charsAfterKeyword = getCharsAfterKeyword(index,content.length());
			sb.append(content.substring(charsBeforeKeyword,charsAfterKeyword));
			sb.append(getPreviewSeprator());
		}
		return sb.toString();
	}
	private String getPreviewSeprator() {
		return "...";
	}
	private int getCharsBeforeKeyword(int index){
		return (index<10)?0:index-10;
	}
	private int getCharsAfterKeyword(int index, int length){
		return (index>length-10)?length:index+10;
	}
	
	public Request getRequestFromSocket() throws IOException, ClassNotFoundException{
		//ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
		return (Request)ois.readObject();
	}
	
	public void sendBackUsingSocketFirst(ArrayList<WebPage> webPages,int pageCount) throws IOException{		
		oos.writeInt(pageCount);
		
		sendBackUsingSocket(webPages);
		
	}
	
	public void sendBackUsingSocket(ArrayList<WebPage> webPages) throws IOException{
		WebPage[] sendData = (WebPage[])webPages.toArray(new WebPage[webPages.size()]);
		oos.writeObject(sendData);
	}

	public ArrayList<WebPage> queryOnePage(String keyword, int page){
		return dao.query(keyword, recordsPerPage, (page-1)*recordsPerPage);
	}
	
	public int queryPageCount(String keyword){
		return dao.queryCount(keyword)/recordsPerPage+1;
	}
	
	public String[] parseKeywords(String keyword){
		return keyword.split(" +");
	}
	public void run(){
			logger.info("New connection accepted " +socket.getInetAddress() + ":" +socket.getPort());

			try {
				 oos = new ObjectOutputStream(socket.getOutputStream());
				 ois = new ObjectInputStream(socket.getInputStream());
				Request request = getRequestFromSocket();
				
				ArrayList<WebPage> webPages = queryOnePage(request.getKeywords(), request.getPage());
				ArrayList<WebPage> webPagesLite = new ArrayList<WebPage>();
				
				for(WebPage webPage : webPages){
					webPage.setContent(getPreview(webPage.getContent(), parseKeywords(request.getKeywords())));					
					webPagesLite.add(webPage);
				}
				
				if(request.getPage()==1){
					sendBackUsingSocketFirst(webPagesLite, queryPageCount(request.getKeywords()));
				}else{
					sendBackUsingSocket(webPagesLite);
				}
				
			} catch (IOException e) {
				logger.error("IOException " +socket.getInetAddress() + ":" +socket.getPort());
			} catch (ClassNotFoundException e) {
				logger.error("ClassNotFoundException " +socket.getInetAddress() + ":" +socket.getPort());
			}finally{
				dao.dispose();
			}
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}
}